package com.terry.imnetty.im;

import cn.hutool.core.lang.Console;
import com.google.protobuf.InvalidProtocolBufferException;
import com.terry.imnetty.bean.msg.ProtoMsg;
import com.terry.imnetty.constant.ProtoInstant;
import com.terry.imnetty.exception.InvalidFrameException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @author tanlvxu
 * @version 1.0
 * @information
 * @date 2021/10/29 17:25
 */
@Slf4j
public class ProtobufDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        Object outmsg = decode0(ctx, in);
        //解析对象失败就等待
        if (outmsg != null) {
            // 获取业务消息
            out.add(outmsg);
        }
    }


    public static Object decode0(ChannelHandlerContext ctx,
                                 ByteBuf in) throws InvalidFrameException, InvalidProtocolBufferException {
        // 标记一下当前的readIndex的位置
        in.markReaderIndex();
        // 判断包头长度
        if (in.readableBytes() < 8) {// 不够包头
            return null;
        }
        //读取魔数
        short magic = in.readShort();
        if (magic != ProtoInstant.MAGIC_CODE) {
            String error = "客户端口令不对:" + ctx.channel().remoteAddress();
            throw new InvalidFrameException(error);
        }
        //读取版本
        short version = in.readShort();
        // 读取传送过来的消息的长度。
        int length = in.readInt();

        // 长度如果小于0
        if (length < 0) {// 非法数据，关闭连接
            ctx.close();
        }

        if (length > in.readableBytes()) {// 读到的消息体长度如果小于传送过来的消息长度
            // 重置读取位置
            in.resetReaderIndex();
            return null;
        }
        Console.log("decoder length=" + in.readableBytes());

        byte[] array = new byte[length];
        in.readBytes(array, 0, length);

        // 字节转成对象
        ProtoMsg.Message outmsg = ProtoMsg.Message.parseFrom(array);

        return outmsg;
    }
}
